package com.hqyj.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hqyj.pojo.User;
import com.hqyj.dao.UserMapper;
import com.hqyj.service.IUserService;
import com.hqyj.util.MdFive;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author rock
 * @since 2021-10-21
 */
@Service
public class UserServiceImpl implements IUserService {
    //mapper injection
    @Autowired(required = false)
    UserMapper userMapper;

    //注入md5工具类
    @Autowired
    MdFive mdFive;

    //注入redis
    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    //设置错误次数
    final int PWD = 3;
    //设置账号的锁定时间
    final int lock = 60;

    @Override
    public HashMap<String, Object> login(User user, HttpSession session) {
        HashMap<String, Object> map = new HashMap<String, Object>();
        //定义密码输入错误的键名
        String keyFail = user.getSysName() + ":fail";
        //定义锁定账户的键名
        String keyLock = user.getSysName() + ":lock";
        //共享角色
        int sysId = userMapper.selectIdByUserName(user.getSysName());
        String sysEmail = userMapper.selectEmailByUsername(user.getSysName());
        session.setAttribute("sysEmail", sysEmail);
        session.setAttribute("sysId", sysId);
        session.setAttribute("USER", user);
        try {
            // 判断锁定账户的键名是否存在
            Object obj = redisTemplate.opsForValue().get(keyLock);
            if (obj != null) {
                //获取剩余时间
                Long time = redisTemplate.getExpire(keyLock, TimeUnit.SECONDS);
                map.put("info", "账号被锁定,你还有" + time + "秒后再重试");
            } else {
                //1 用户令牌(用户和密码对象)
                UsernamePasswordToken token = new UsernamePasswordToken(user.getSysName(), user.getSysPwd());
                //2 创建shiro的用户对象
                Subject su = SecurityUtils.getSubject();
                //3 登录
                su.login(token);
                map.put("info", "登录成功");
                redisTemplate.delete(keyFail);
            }

        } catch (UnknownAccountException u) {
            u.printStackTrace();
            map.put("info", "用户名不正确");
            System.out.println("用户名不正确");
        } catch (IncorrectCredentialsException e) {
            map.put("info", "密码不正确");
            System.out.println("密码不正确");
            //设置密码错误+1
            redisTemplate.opsForValue().increment(keyFail, 1);

            //取出密码错误键值
            int num = (Integer) redisTemplate.opsForValue().get(keyFail);
            //设置密码错误的失效时间
            redisTemplate.opsForValue().set(keyFail, num, 120, TimeUnit.SECONDS);

            int i = PWD - num;
            if (i > 0) {
                map.put("info", "密码错误,你还有" + i + "次机会");
            } else {
                map.put("info", "你输入密码次数太多，已经被锁定");
                //设置账号锁定
                redisTemplate.opsForValue().set(keyLock, true, lock, TimeUnit.SECONDS);
                //删除密码错误的建
                redisTemplate.delete(keyFail);

            }

        }

        return map;
    }

    @Override
    public HashMap<String, Object> queryAll(User user) {
//        HashMap<String, Object> map = new HashMap<>();
//        QueryWrapper queryWrapper = new QueryWrapper();
//        List<User> userList = userMapper.selectList(null);
//        System.out.println(userList);
//        map.put("list", userList);
//        return map;
        HashMap<String, Object> map = new HashMap<String, Object>();
        //定义分页对象
        Page<User> page = new Page<>(user.getPage(), user.getRow());

        /*-------------mybatit plus的分页条件查询 -------------- */
        //查询分页
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //编号查询
        queryWrapper.eq(user.getSysId() != null, "sys_id", user.getSysId());
        //用户名模糊查询
        queryWrapper.like(!StringUtils.isEmpty(user.getSysName()) && user.getSysName() != null, "sys_name", user.getSysName());

        /*-------------自定义的的分页条件查询 -------------- */
        //Page<User> aList = userMapeer.selectByCon(page,user);
        //定义当前页的建名
        String curkey = "admin:list:" + user.getPage() + ":" + user.getRow();
        //定义总页数的建名
        String totalPageKey = "admin:totalPage:" + user.getPage() + ":" + user.getRow();
        //定义总条数
        String totalKey = "admin:total";
        //定义当前页
        String curPageKey = "admin:curPage:" + user.getPage() + ":" + user.getRow();
        //定义上一页
        String prePageKey = "admin:prePage:" + user.getPage() + ":" + user.getRow();
        //定义当前页
        String nextPageKey = "admin:nextPage:" + user.getPage() + ":" + user.getRow();
        //判断redis是否有缓存
        Object obj = redisTemplate.opsForValue().get(curkey);
        if (obj != null) {
            //当前页集合
            map.put("list", redisTemplate.opsForValue().get(curkey));
            //总页数
            map.put("totalPage", redisTemplate.opsForValue().get(totalPageKey));
            Integer totalPage = (Integer) redisTemplate.opsForValue().get(totalPageKey);
            //总条数
            map.put("total", redisTemplate.opsForValue().get(totalKey));
            //当前页
            map.put("curPage", user.getPage());

            if (user.getPage() == 1) {
                //上一页
                map.put("prePage", 1);
            } else {
                map.put("prePage", redisTemplate.opsForValue().get(prePageKey));
            }

            if (user.getPage() == totalPage) {
                //下一页
                map.put("nextPage", totalPage);
            } else {
                map.put("nextPage", user.getPage() + 1);
            }

        } else {
            //查询数据库
            Page<User> aList = userMapper.selectPage(page, queryWrapper);
            //当前页集合
            map.put("list", aList.getRecords());
            //总页数
            map.put("totalPage", aList.getPages());
            //总条数
            map.put("total", aList.getTotal());
            //当前页
            map.put("curPage", user.getPage());
            if (user.getPage() == 1) {
                //上一页
                map.put("prePage", 1);
                redisTemplate.opsForValue().set(prePageKey, 1, 60, TimeUnit.SECONDS);
            } else {
                map.put("prePage", user.getPage() - 1);
                redisTemplate.opsForValue().set(prePageKey, user.getPage() - 1, 60, TimeUnit.SECONDS);
            }

            if (user.getPage() == aList.getPages()) {
                //下一页
                map.put("nextPage", aList.getPages());

                redisTemplate.opsForValue().set(nextPageKey, aList.getPages(), 60, TimeUnit.SECONDS);
            } else {
                map.put("nextPage", user.getPage() + 1);
                redisTemplate.opsForValue().set(nextPageKey, user.getPage() + 1, 60, TimeUnit.SECONDS);
            }

            //每页显示条数
            map.put("row", user.getRow());

//            //添加数据到缓存中
//            redisTemplate.opsForValue().set(curkey,aList.getRecords(),60,TimeUnit.SECONDS);
//            redisTemplate.opsForValue().set(totalPageKey,aList.getPages(),60,TimeUnit.SECONDS);
//            redisTemplate.opsForValue().set(totalKey,aList.getTotal(),60,TimeUnit.SECONDS);
//            redisTemplate.opsForValue().set(curPageKey,user.getPage(),60,TimeUnit.SECONDS);

        }


        return map;
    }

    @Override
    public HashMap<String, Object> update(User user) {
        HashMap<String, Object> map = new HashMap<>();
        //条件构造器
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //根据用户名查询条件
        queryWrapper.eq("sys_name", user.getSysName());
        //是否重名
        List<User> list = userMapper.selectList(queryWrapper);

        if (list.size() > 1) {
            map.put("info", "用户名重名");
        } else {
            String salt = UUID.randomUUID() + "";
            user.setSalt(salt);
            //加密密码
            String p = mdFive.encrypt(user.getSysPwd(), salt);
            user.setSysPwd(p);
            //修改
            int num = userMapper.updateById(user);
            if (num > 0) {
                map.put("info", "保存成功");
            } else {
                map.put("info", "保存错误");
            }
        }
        return map;
    }

    @Override
    public HashMap<String, Object> addUser(User user) {
        HashMap<String, Object> map = new HashMap<>();
        //条件构造器
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //根据用户名查询条件
        queryWrapper.eq("sys_name", user.getSysName());
        //是否重名
        List<User> list = userMapper.selectList(queryWrapper);
        if (list.size() > 0) {
            map.put("info", "用户名重名");
        } else {
            String salt = UUID.randomUUID() + "";
            user.setSalt(salt);
            //加密密码
            String p = mdFive.encrypt(user.getSysPwd(), salt);
            user.setSysPwd(p);
            //修改
            int num = userMapper.insert(user);
            if (num > 0) {
                map.put("info", "保存成功");
            } else {
                map.put("info", "保存错误");
            }
        }
        return map;
    }

    @Override
    public HashMap<String, Object> delUser(Integer id) {
        HashMap<String, Object> map = new HashMap<>();
        //删除
        int num = userMapper.deleteById(id);
        if (num == 1) {
            map.put("info", "删除成功");
        } else {
            map.put("info", "删除失败");
        }
        return map;
    }

    @Override
    public HashMap<String, Object> updatePwd(String pwd, String sysName) {
        HashMap<String, Object> map = new HashMap<>();

        String salt = UUID.randomUUID() + "";
        //加密密码
        String p = mdFive.encrypt(pwd, salt);
        //修改
        int num = userMapper.updatePwd(sysName,p,salt);
        if (num > 0) {
            map.put("info", "修改成功");
        } else {
            map.put("info", "修改失败");
        }

        return map;
    }
}
